package crond

import (
	"context"
	"encoding/json"
	"strings"
	"time"

	"device-admin/config/mysql"
	"device-admin/config/redis"
	"device-admin/internal/app/grpc/client"
	"device-admin/internal/app/grpc/protoc/system_admin"
	"device-admin/internal/define"
	"device-admin/internal/models"

	"192.168.1.75/go-pkg/logx"
	"github.com/shopspring/decimal"
)

// DailyReport 日统计
func DailyReport(merchantID ...string) interface{} {
	var (
		db             = mysql.NewDB()
		dailyReportMap = make(map[string]map[string]interface{})
	)
	// 最近一周每日里程
	type latestWeekDailyOdometerType struct {
		Date            string `json:"date" gorm:"column:date"`                         // 日期
		RunningOdometer int64  `json:"running_odometer" gorm:"column:running_odometer"` // 运行里程
	}
	// 最近一周每日任务统计
	type latestWeekDailyTaskRecordType struct {
		Date  string `json:"date" gorm:"column:date"`   // 日期
		Count int64  `json:"count" gorm:"column:count"` // 数量
	}
	// 最近一周活跃设备统计
	type latestWeekDailyActiveDeviceType struct {
		Date    string `json:"date" gorm:"column:date"`       // 日期
		Percent int64  `json:"percent" gorm:"column:percent"` // 数量
	}
	// 七天前的开始时间戳
	_7DayBeforeTimestamp := int(time.Now().Unix()) - 6*24*3600 - time.Now().Hour()*3600 - time.Now().Minute()*60 - time.Now().Second() + 1
	// 最近七天的日期
	lastest7Days := []string{
		time.Unix(int64(_7DayBeforeTimestamp), 0).Format("2006-01-02"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*1), 0).Format("2006-01-02"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*2), 0).Format("2006-01-02"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*3), 0).Format("2006-01-02"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*4), 0).Format("2006-01-02"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*5), 0).Format("2006-01-02"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*6), 0).Format("2006-01-02"),
	}
	// 整数类型的，月和天前面不补零
	lastest7DaysInt := []string{
		time.Unix(int64(_7DayBeforeTimestamp), 0).Format("2006-1-2"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*1), 0).Format("2006-1-2"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*2), 0).Format("2006-1-2"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*3), 0).Format("2006-1-2"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*4), 0).Format("2006-1-2"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*5), 0).Format("2006-1-2"),
		time.Unix(int64(_7DayBeforeTimestamp+3600*24*6), 0).Format("2006-1-2"),
	}

	// 通过GRPC获取商户列表
	systemAdminCli, err := client.GetSystemAdminClient()
	if err != nil {
		logx.Error(context.Background(), "GetSystemAdminClient error")
		return nil
	}

	rsp, err := systemAdminCli.MerchantList(context.Background(), &system_admin.MerchantListReq{MerchantId: "1"})
	if err != nil || rsp.Code != 0 {
		logx.Error(context.Background(), "Get MerchantList by grpc error")
		return nil
	}

	rsp.List = append(rsp.List, &system_admin.MerchantListRspMerchant{
		MerchantName: "系统平台",
		MerchantId:   "1",
		MerchantPath: "",
	})

	startAt := time.Now().Unix()
	// 遍历每个商户，进行数据查询处理
	for _, merchantRecord := range rsp.List {
		merchantID := merchantRecord.MerchantId
		merchantPath := strings.Join([]string{merchantRecord.MerchantPath, merchantRecord.MerchantId}, ">")
		var (
			// 设备总数
			totalDevice int64
			// 今日开机数
			dailyActiveNum float64
			todayActiveNum int64
			// 今日设备活跃百分比
			todayActivePercent float64
			// 总里程
			totalRunningOdometer int64
			// 最近一周每日里程
			latestWeekDailyOdometer []latestWeekDailyOdometerType
			// 最近一周每日任务统计
			latestWeekDailyTaskRecords []latestWeekDailyTaskRecordType
			// 最近一周活跃设备百分比
			latestWeekDailyActiveDevice []latestWeekDailyActiveDeviceType
			// 设备分布
			deviceLocation []struct {
				CityID string `json:"city_id" gorm:"column:city_id"`
				Count  int64  `json:"count" gorm:"column:count"`
			}
		)
		dailyReportMap[merchantID] = make(map[string]interface{}) // 商户信息map初始化
		// 设备总数
		{
			db.Model(&models.Device{}).
				Where("merchant_path LIKE ?", merchantPath+"%").
				// 排除掉返厂的设备
				Where("merchant_id > ?", 1).
				Count(&totalDevice)
			// 设备总数
			dailyReportMap[merchantID]["total_device"] = totalDevice
		}
		// 每日开机数
		// 获取每台机器的总天数
		{
			var devicesActiveDays []struct {
				TotalOnlineDays int64 `gorm:"column:total_online_days"`
				FirstOnlineTime int64 `gorm:"column:first_online_time"`
			}
			tx := db.Table(models.Device{}.TableName()+" d").
				Joins("JOIN "+models.DeviceActiveDuration{}.TableName()+" dad ON d.robot_id = dad.robot_id").
				Where("d.merchant_path LIKE ?", merchantPath+"%").
				Where("d.merchant_id > ?", 1).
				Select(
					"Count(dad.date) as total_online_days",
					"MIN(dad.created_at) as first_online_time",
				).
				Group("dad.robot_id")

			tx.Find(&devicesActiveDays)
			for _, deviceActiveDays := range devicesActiveDays {
				usedDays := (time.Now().Unix() - deviceActiveDays.FirstOnlineTime) / 86400
				if (time.Now().Unix()-deviceActiveDays.FirstOnlineTime)%86400 > 0 {
					usedDays += 1
				}
				if usedDays == 0 {
					continue
				}
				if deviceActiveDays.TotalOnlineDays > usedDays {
					dailyActiveNum += 1
				} else {
					dailyActiveNum += float64(deviceActiveDays.TotalOnlineDays) / float64(usedDays)
				}
			}

			dailyReportMap[merchantID]["total_online_device"], _ = decimal.NewFromFloat(dailyActiveNum).Truncate(1).Float64()
			time.Sleep(time.Second * 1)
		}
		// 更新设备活跃百分比
		{
			// 今日活跃设备
			{
				tx := db.Table(models.Device{}.TableName()+" d").
					Joins("JOIN "+models.DeviceActiveDuration{}.TableName()+" dad ON d.robot_id = dad.robot_id").
					Where("d.merchant_path LIKE ?", merchantPath+"%").
					Where("d.merchant_id > ?", 1).
					Where("dad.date = ?", time.Now().Format("2006-1-2"))

				tx.Select(
					"COUNT(*) as count",
				).Take(&todayActiveNum)
			}
			if totalDevice == 0 || todayActiveNum == 0 {
				todayActivePercent = 0
			} else {
				if todayActiveNum >= totalDevice {
					todayActivePercent = 100
				} else {
					todayActivePercent = float64(todayActiveNum * 100 / totalDevice)
					todayActivePercent, _ = decimal.NewFromFloat(todayActivePercent).Truncate(0).Float64()
				}
			}
			db.Model(&models.DeviceDailyReport{}).
				Where(models.DeviceDailyReport{
					Name:       "active_device_percent",
					Date:       time.Now().Format("2006-01-02"),
					MerchantID: merchantID,
				}).
				Assign(models.DeviceDailyReport{
					Name:       "active_device_percent",
					Date:       time.Now().Format("2006-01-02"),
					MerchantID: merchantID,
					Value:      todayActivePercent,
				}).
				FirstOrCreate(&models.DeviceDailyReport{})
			time.Sleep(time.Second * 1)
		}

		// 总里程
		{
			var count int64
			tx := db.Table(models.Device{}.TableName()+" d").
				Joins("JOIN "+models.DeviceActiveDuration{}.TableName()+" dad ON d.robot_id = dad.robot_id").
				Where("d.merchant_path LIKE ?", merchantPath+"%").
				Where("d.merchant_id > ?", 1)
			tx.Count(&count)
			if count > 0 {
				tx.Select("SUM(dad.running_odometer) as running_odometer").
					Take(&totalRunningOdometer)
			}
			// 保存到map
			dailyReportMap[merchantID]["total_running_odometer"] = totalRunningOdometer
		}

		// 设备分布统计
		{
			// 设备和位置联通，统计每个市的设备数量
			db.Model(&models.Device{}).
				Joins("JOIN location ON device.location_id = location.id").
				Where("device.merchant_path LIKE ?", merchantPath+"%").
				Where("device.merchant_id > ?", 1).
				Select(
					"location.city_id",
					"COUNT(device.id) as count",
				).
				Group("location.city_id").
				Find(&deviceLocation)
			// 保存到map
			dailyReportMap[merchantID]["device_location_distribution"] = deviceLocation
		}

		// 最近一周每日里程
		{
			tx := db.Table(models.Device{}.TableName()+" d").
				Joins("JOIN "+models.DeviceActiveDuration{}.TableName()+" dad ON d.robot_id = dad.robot_id").
				Where("d.merchant_path LIKE ?", merchantPath+"%").
				Where("d.merchant_id > ?", 1)
			// 近一周的每日里程
			tx.Select(
				"dad.date",
				"SUM(dad.running_odometer) as running_odometer",
			).
				Where("dad.date IN ?", lastest7DaysInt).
				Group("dad.date").
				Find(&latestWeekDailyOdometer)
			// 查询结果转为map
			latestWeekDailyOdometerMap := map[string]*latestWeekDailyOdometerType{}
			for _, record := range latestWeekDailyOdometer {
				latestWeekDailyOdometerMap[record.Date] = &latestWeekDailyOdometerType{
					Date:            record.Date,
					RunningOdometer: record.RunningOdometer,
				}
			}
			// 遍历最近7天，没有的补0
			res := []latestWeekDailyOdometerType{}
			for _, date := range lastest7DaysInt {
				if latestWeekDailyOdometerMap[date] == nil {
					res = append(res, latestWeekDailyOdometerType{
						Date:            date,
						RunningOdometer: 0,
					})
				} else {
					res = append(res, latestWeekDailyOdometerType{
						Date:            date,
						RunningOdometer: latestWeekDailyOdometerMap[date].RunningOdometer,
					})
				}
			}
			// 保存到map
			dailyReportMap[merchantID]["latest_week_daily_odometer"] = res
		}
		// 最近一周任务事件通知
		{
			for _, createdDate := range lastest7Days {
				var latestWeekDailyTaskRecord latestWeekDailyTaskRecordType
				tx := db.Table(models.Device{}.TableName() + " d").
					Joins("JOIN " + models.TaskRecord{}.TableName() + " t ON d.robot_id = t.robot_id")

				if merchantID == "1" {
					tx = tx.Where("d.merchant_path LIKE ?", ">1>%")
				} else {
					tx = tx.Where("d.merchant_path LIKE ?", merchantPath+"%")
				}

				tx.Select(
					"t.created_date as date",
					"COUNT(*) as count",
				).
					Where("t.created_date = ?", createdDate).
					Group("t.created_date").
					Take(&latestWeekDailyTaskRecord)
				latestWeekDailyTaskRecords = append(latestWeekDailyTaskRecords, latestWeekDailyTaskRecord)
			}
			// 查询结果转为map
			latestWeekDailyTaskRecordMap := map[string]*latestWeekDailyTaskRecordType{}
			for _, record := range latestWeekDailyTaskRecords {
				latestWeekDailyTaskRecordMap[record.Date] = &latestWeekDailyTaskRecordType{
					Date:  record.Date,
					Count: record.Count,
				}
			}
			// 遍历最近7天，没有的补0
			res := []latestWeekDailyTaskRecordType{}
			for _, date := range lastest7Days {
				if latestWeekDailyTaskRecordMap[date] == nil {
					res = append(res, latestWeekDailyTaskRecordType{
						Date:  date,
						Count: 0,
					})
				} else {
					res = append(res, latestWeekDailyTaskRecordType{
						Date:  date,
						Count: latestWeekDailyTaskRecordMap[date].Count,
					})
				}
			}
			// 保存到map
			dailyReportMap[merchantID]["latest_week_daily_task_record"] = res
		}
		// 最近一周活跃设备百分比
		{
			tx := db.Model(&models.DeviceDailyReport{})
			tx = tx.Where("merchant_id = ?", merchantRecord.MerchantId)
			tx.Select(
				"date",
				"value as percent",
			).
				Where("date IN ?", lastest7Days).
				Where("name = ?", "active_device_percent").
				Find(&latestWeekDailyActiveDevice)
			// 查询结果转为map
			latestWeekDailyActiveDeviceMap := map[string]*latestWeekDailyActiveDeviceType{}
			for _, record := range latestWeekDailyActiveDevice {
				latestWeekDailyActiveDeviceMap[record.Date] = &latestWeekDailyActiveDeviceType{
					Date:    record.Date,
					Percent: record.Percent,
				}
			}
			// 遍历最近7天，没有的补0
			res := []latestWeekDailyActiveDeviceType{}
			for _, date := range lastest7Days {
				if latestWeekDailyActiveDeviceMap[date] == nil {
					res = append(res, latestWeekDailyActiveDeviceType{
						Date:    date,
						Percent: 0,
					})
				} else {
					res = append(res, latestWeekDailyActiveDeviceType{
						Date:    date,
						Percent: latestWeekDailyActiveDeviceMap[date].Percent,
					})
				}
			}
			// 保存到map
			dailyReportMap[merchantID]["latest_week_active_device_percent"] = res
		}
		// 缓存结果至redis
		timeoutCtx, cancel := context.WithTimeout(context.Background(), time.Second*3)
		defer cancel()
		js, _ := json.Marshal(dailyReportMap[merchantID])
		redis.NewDB().HMSet(timeoutCtx, define.HomePageReport, merchantRecord.MerchantId, js)
	}
	logx.Info(context.Background(), "device DailyReport duration(second)", logx.Int64("second", time.Now().Unix()-startAt))
	if len(merchantID) > 0 {
		return dailyReportMap[merchantID[0]]
	}
	return nil
}
